package middleware

import (
	"context"
	"time"

	"sysu-giep/pkg/logger"
	"sysu-giep/pkg/response"

	"github.com/gin-contrib/requestid"
	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
	"go.uber.org/zap"
)

// RequestID 请求ID中间件
func RequestID() gin.HandlerFunc {
	return requestid.New(
		requestid.WithGenerator(func() string {
			return uuid.NewString()
		}),
		requestid.WithCustomHeaderStrKey("X-Request-ID"),
	)
}

// Logger 日志中间件
func Logger() gin.HandlerFunc {
	return gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string {
		// 获取请求ID
		requestID := param.Keys["requestid"]
		if requestID == nil {
			requestID = "unknown"
		}

		// 记录请求日志
		logger.Info("HTTP请求",
			logger.String("request_id", requestID.(string)),
			logger.String("method", param.Method),
			logger.String("path", param.Path),
			logger.String("client_ip", param.ClientIP),
			logger.String("user_agent", param.Request.UserAgent()),
			logger.Int("status_code", param.StatusCode),
			zap.Duration("latency", param.Latency),
			logger.Int("body_size", param.BodySize),
		)

		return ""
	})
}

// Recovery 恢复中间件
func Recovery() gin.HandlerFunc {
	return gin.CustomRecovery(func(c *gin.Context, recovered interface{}) {
		// 获取请求ID
		requestID := c.GetString("requestid")
		if requestID == "" {
			requestID = "unknown"
		}

		// 记录错误日志
		zap.L().Error("HTTP请求异常",
			zap.String("request_id", requestID),
			zap.String("method", c.Request.Method),
			zap.String("path", c.Request.URL.Path),
			zap.String("client_ip", c.ClientIP()),
			zap.Any("error", recovered),
		)

		// 返回错误响应
		response.InternalServerError(c, "服务器内部错误")
	})
}

// Timeout 超时中间件
func Timeout(timeout time.Duration) gin.HandlerFunc {
	return func(c *gin.Context) {
		// 设置超时上下文
		ctx, cancel := context.WithTimeout(c.Request.Context(), timeout)
		defer cancel()

		c.Request = c.Request.WithContext(ctx)

		// 创建完成通道
		done := make(chan bool, 1)
		go func() {
			c.Next()
			done <- true
		}()

		select {
		case <-done:
			// 请求正常完成
		case <-ctx.Done():
			// 请求超时
			logger.Warn("HTTP请求超时",
				logger.String("request_id", c.GetString("requestid")),
				logger.String("method", c.Request.Method),
				logger.String("path", c.Request.URL.Path),
				zap.Duration("timeout", timeout),
			)
			response.Error(c, 408, "请求超时")
			c.Abort()
		}
	}
}

// RateLimit 限流中间件
func RateLimit(limit int, window time.Duration) gin.HandlerFunc {
	// 使用内存存储限流计数器
	counters := make(map[string]*rateLimitCounter)

	return func(c *gin.Context) {
		key := c.ClientIP()
		now := time.Now()

		// 获取或创建计数器
		counter, exists := counters[key]
		if !exists || now.Sub(counter.windowStart) >= window {
			counter = &rateLimitCounter{
				count:       1,
				windowStart: now,
			}
			counters[key] = counter
		} else {
			counter.count++
		}

		// 检查是否超过限制
		if counter.count > limit {
			logger.Warn("请求频率过高",
				logger.String("client_ip", key),
				logger.String("method", c.Request.Method),
				logger.String("path", c.Request.URL.Path),
				logger.Int("count", counter.count),
				logger.Int("limit", limit),
			)
			response.Error(c, 429, "请求过于频繁")
			c.Abort()
			return
		}

		c.Next()
	}
}

// rateLimitCounter 限流计数器
type rateLimitCounter struct {
	count       int
	windowStart time.Time
}
